<?php

if (!defined('BASEPATH'))
	exit('No direct script access allowed');

class Import extends MY_Admin_Controller {
	protected $processItem;
	protected $processMessage;
	protected $feedUrl;
	protected $productFeedName;
	protected $categoryFeedName;
	protected $ringSizeFeedName;
	protected $toSyncInTranslations;
	protected $notSyncInTranslations;
	
	/**
	 * 
	 * The constructor
	 */
	function __construct() {
		parent::__construct();
		
		$this->load->library('csv_reader');
		$this->load->model('product_model');
		$this->load->model('category_model');
		$this->load->model('product_category_model');
		$this->load->model('images_model');
		$this->load->model('large_images_model');
		$this->load->model('size_model');
		$this->load->model('product_size_model');
		$this->load->model('logs_model');
		
		

		//message array
		$this->processMessage = array (
			'1'	=> 'all records were marked for deletion',
			'2'	=> 'products.csv --> product and product_sub',
			'3'	=> 'categories.csv --> product_category',
			'4'	=> 'ringsizes.csv --> size',
			'5'	=> 'the marked products were removed',
			'6'	=> 'sku,name updated'
		);
		
		//default process
		$this->processItem = 1;		
		
		//feed url
		$this->feedUrl = $this->config->item('FEED_URL');
		
		//product feed
		$this->productFeedName = 'products.csv';
		
		//category feed
		$this->categoryFeedName = 'categories.csv';
		
		//ring size feed
		$this->ringSizeFeedName = 'ringsizes.csv';
		
		//allowed syncable fields in the translated nodes
		$this->toSyncInTranslations = $this->config->item('FEED_SYNC_IN_TRANSLATIONS');
		
		//not allowed syncable fields in the translated nodes
		$this->notSyncInTranslations = $this->config->item('NOT_SYNC_THEM');		

	}	
	
	/**
	 * 
	 * The entry point of the import routine, it will controll the whole process
	 */
	public function start(){
		try {	
			if (ob_get_level() == 0){
				ob_start();			
			}
			//no time limit
			set_time_limit(0);
			error_reporting(E_ALL);
			ini_set('display_errors', '1');	
			ini_set("memory_limit","2000M");		
			
			$this->db->save_queries = false;
			//consistency check
			$this->consistencyCheck();		
			
			//let's begin a transaction
			$this->db->trans_begin();
			
			echo 'A new import transaction has been strated.<br />';
			
			//import queries
			self::process();	
			
			//everything was just fine so we can commit the transaction
			$this->db->trans_commit();
			
			echo 'The import routine was finished successfully.<br />';
			
			ob_end_flush();
		}
		catch (Exception $e) {
			//An exception has been thrown, we must rollback the transaction
		    $this->db->trans_rollback();
		    
		    show_error($e->getMessage() . '<br /> The transaction is rolling back...', 417);
		}		
		
	}
	
	/**
	 * 
	 * Calls the process actions recursive
	 */
	private function process() {
		$method = 'process' . $this->processItem;
		if (method_exists($this, $method)) {
        	echo "Process $this->processItem ... ";
       		echo str_pad('',4096)."\n";    
       		
	        ob_flush();
	        flush();
	        
			call_user_func(array($this, $method));
			echo $this->processMessage[$this->processItem] . '<br />';  
			
	        ob_flush();
	        flush();
	        			
	        $this->processItem++;	
	        self::process($this->processItem);			
		}			
	}
	
	private function consistencyCheck() {
		//products.csv
	
		if (!file_exists(BASEPATH . '../datafeed/' . $this->productFeedName)) {
			echo 'products.csv is missing.';
			die;		
		}	
		
		//categories.csv
		if (!file_exists(BASEPATH . '../datafeed/' . $this->categoryFeedName)) {
			echo 'catgories.csv is missing';
			die;	
		}	

		//ringsize.csv
		if (!file_exists(BASEPATH . '../datafeed/' . $this->ringSizeFeedName)) {
			echo 'ringsize.csv is missing';
			die;	
		}	

		//add to logs
		$this->logs_model->user_id = $this->access->getUserId();
		$this->logs_model->datetime = date('Y-m-d h:i:s', time());
		$this->logs_model->insert();
	}
	
	/**
	 * 
	 * Marks every record for deletion
	 */
	protected function process1() {
		$this->product_model->updateExternData(array('marked_deletion' => 1));	
		
		$this->category_model->updateExternData(array('marked_deletion' => 1));

		$this->product_category_model->updateExternData(array('marked_deletion' => 1));
	}

	/**
	 * 
	 * Imports the users from the source db export-Dec-7nd.csv --> product and product_sub
	 */
	protected function process2(){		
		
		//todo remove after testing
		//$this->db->truncate('products');
		
		//set up for the parser
		$content = array ();
		$p_NamedFields = TRUE;
	
		$file = fopen($this->feedUrl . $this->productFeedName, 'r');
		
	    if($p_NamedFields) {
            $fields = fgetcsv($file, 0, ',', '"');
        }	
		$latestParentId = 0;
		$isParent = false;        

		//loading the products from the feed
		$counter = 0;

        while( ($row = fgetcsv($file, 0, ',', '"')) !== false ) {        
            if( $row[0] != null ) { // skip empty lines
                if( $p_NamedFields ) {
                    $items = array();
                    
                    // I prefer to fill the array with values of defined fields
                    foreach( $fields as $id => $field ) {
                        if( isset($row[$id]) ) {
                            $items[$field] = $row[$id];    
                        }
                    }
                    $content[] = $items;
                } 
                else {
                    $content[] = $row;
                }
            }
            
            $product = $content['0'];
            $product['sku_pd'] = $product['sku'];
            $content = array();          

			//check if sync is needed
			$existingProduct = $this->product_model->get_by_sku_pd($product['sku_pd'], $this->config->item('def_language_id'));
			//$existingProduct = false;
			
			//checking the type of the product if it is new in the system
			if (!$existingProduct) {
				if ((preg_match('/^[a-zA-Z0-9\/]*$/', $product['sku_pd'])) && ($product['type'] == 'configurable')) {
					$product['parent_id'] = 0;
					$isParent = true;
				}
				else {
					$product['parent_id'] = $latestParentId;
					$isParent = false;	
				}
				
				//getting the associated files from the datafeed's server	
				if ((!empty($product['flash_file_1'])) && (!file_exists(FLASH_IMAGE_PATH . $product['flash_file_1'] . '.swf'))) {
					copy($this->config->item('FLASH_IMAGE') . $product['flash_file_1'] . '.swf', FLASH_IMAGE_PATH . $product['flash_file_1'] . '.swf');	
				}
				
				if ((!empty($product['flash_file_2'])) && (!file_exists(FLASH_IMAGE_PATH . $product['flash_file_2'] . '.swf'))) {
					copy($this->config->item('FLASH_IMAGE') . $product['flash_file_2'] . '.swf', FLASH_IMAGE_PATH . $product['flash_file_2'] . '.swf');	
				}
			}
			
			//adding 0/1 for the status field
			if ((isset($product['status'])) and ($product['status'] == 'Enabled')) {
				$product['status'] = '1';	
			}
			else {
				$product['status'] = '0';		
			}
			
			//removing the non requested fields from the feed
			$neededFields = array_intersect_assoc($this->product_model->fields, $product);
			foreach ($this->product_model->fields as $key => $vale) {
				if (array_key_exists($key, $product)) {
					$this->product_model->fields[$key] = $product[$key];	
				}
			}
			$this->product_model->fields['sku_pd'] = $product['sku'];
			
			//setting to default language
			$this->product_model->fields['language_id'] = $this->config->item('def_language_id');
			$this->product_model->fields['imported'] = 1;
			//contains_sale_item yes/no
			$this->product_model->fields['contains_sale_item'] = ($this->product_model->fields['contains_sale_item'] == 'yes') ? 1 : 0;
			
			$productObj = $this->product_model->fields_to_object();
			
			if (!$existingProduct) {
				$productId = 0;
				if ($isParent) {
					$productId = $productObj->insert();
					$latestParentId = $productId;	
				}
				else{
					$productId = $productObj->insert();	
				}
				
				//creating relations with the images
				$imageArr = explode(',', $product['image']);
				$smallImageArr = explode(',', $product['small_image']);
				$thumbImageArr = explode(',', $product['thumbnail']);
				
				$sort = 0;
				$number = 0;
				foreach ($imageArr as $image) {
		        	if (!empty($image)) {
		        		if ((!file_exists(NORMAL_IMAGE_PATH . $this->obtainFileName($image)))) {
							copy($this->config->item('NORMAL_IMAGE') . $image, NORMAL_IMAGE_PATH . $this->obtainFileName($image));
		        		}
						$this->images_model->fields['url'] =  $this->obtainFileName($image);
						$this->images_model->fields['product_id'] = $productId;
						$this->images_model->fields['sort'] = $sort;
						$sort++;
						$this->images_model->fields_to_object()->insert();
						if (isset($smallImageArr[$number])) {
							$smallImage = $smallImageArr[$number];
							if (!empty($smallImage)) {
								if ((!file_exists(SMALL_IMAGE_PATH . $this->obtainFileName($image)))) {
									copy($this->config->item('SMALL_IMAGE') . $smallImage, SMALL_IMAGE_PATH . $this->obtainFileName($image));
								}
							}						
						}
						
						if (isset($thumbImageArr[$number])) {
							$thumbImage = $thumbImageArr[$number];
							if (!empty($thumbImage)) {
								if ((!file_exists(THUMB_IMAGE_PATH . $this->obtainFileName($image)))) {
									copy($this->config->item('THUMB_IMAGE') . $thumbImage, THUMB_IMAGE_PATH . $this->obtainFileName($image));
								}
							}						
						}						
						$number++;
					}
				}
				/*
				$smallImageArr = explode(',', $product['small_image']);
				foreach ($smallImageArr as $image) {
		        	if (!empty($image)) {
		        		if ((!file_exists(SMALL_IMAGE_PATH . $this->obtainFileName($image)))) {
							copy($this->config->item('SMALL_IMAGE') . $image, SMALL_IMAGE_PATH . $this->obtainFileName($image));
		        		}
					}
				}*/
				/*
				$thumbImageArr = explode(',', $product['thumbnail']);
				foreach ($thumbImageArr as $image) {
		        	if (!empty($image)) {
		        		if ((!file_exists(THUMB_IMAGE_PATH . $this->obtainFileName($image)))) {
							copy($this->config->item('THUMB_IMAGE') . $image, THUMB_IMAGE_PATH . $this->obtainFileName($image));
		        		}
					}
				}				
				*/
				//creating relations with the large_images
				$imageArr = explode(',', $product['large_image']);
				$sort = 0;
				foreach ($imageArr as $image) {
		        	if (!empty($image)) {
		        		if (!file_exists(LARGE_IMAGE_PATH . $this->obtainFileName($image))) {
							copy($this->config->item('LARGE_IMAGE') . $image, LARGE_IMAGE_PATH . $this->obtainFileName($image));
		        		}
						$this->large_images_model->fields['url'] =  $this->obtainFileName($image);
						$this->large_images_model->fields['product_id'] = $productId;
						$this->large_images_model->fields['sort'] = $sort;
						$sort++;
						$this->large_images_model->fields_to_object()->insert();
					}
				}							
			}
			else {
				//if there were differences I should apply them to it's translated childs also
				if ($this->sync($existingProduct, $productObj)) {
					$translations = $this->product_model->getAll(array('sku_pd' => $existingProduct->sku_pd), array('language_id' => $this->config->item('def_language_id')));
					foreach ($translations->result() as $translation) {
						$this->syncTranslation($translation->id, $productObj->to_array());
					}
				}
				//removing the deletion marker
				else {
					$existingProduct->marked_deletion = 0;	
					$existingProduct->update();
				}				
			}
			
			
		
			
			//$this->db->flush_cache();
			//$this->db->stop_cache();
			
			echo $product['sku'] . ' ' . ++$counter . '<br />';
	        ob_flush();
	        flush();  
		}
		fclose($file);

	}	
	
	/**
	 * 
	 * Imports the users from the source db rom_categories_data.csv --> product_category
	 */
	protected function process3(){
		//todo remove after testing
		//$this->db->truncate('category');
		//$this->db->truncate('product_category_mn');
		
		//set up for the parser
		$product = '';
		$previousSku = '';		
		$content = array ();
		$p_NamedFields = TRUE;
		$file = fopen($this->feedUrl . $this->categoryFeedName, 'r');
	    if($p_NamedFields) {
            $fields = fgetcsv($file, 4096, ',', '"');
        }	
  
        	
		//loading the categories from the feed
        while( ($row = fgetcsv($file, 4096, ',', '"')) != false ) {        
			if ($row[0] != $previousSku) {
				$previousSku = $row[0];
				$product = $this->product_model->get_by_sku_pd($row[0], $this->config->item('def_language_id'));
			}
			echo $row[0] . ' ---> ' . $row[1] . '<br />';
	        ob_flush();
	        flush();  
	    
	        if ((isset($product)) && (is_object($product))) {		
				$this->createNode(explode (' > ', $row[1]), 0, 0, $product->id);	
	        }	
		}
	}	

	/**
	 * 
	 * Imports the users from the source db rom_ringsizes_data.csv --> size
	 */
	protected function process4(){
		$this->product_size_model->delete('imported = 1');
	
		//set up for the parser
		$product = '';
		$previousSku = '';		
		$content = array ();
		$p_NamedFields = TRUE;
		$file = fopen($this->feedUrl . $this->ringSizeFeedName, 'r');
	    if($p_NamedFields) {
            $fields = fgetcsv($file, 4096, ',', '"');
        }	
  
        	
		//loading the ring sizes from the feed
		//$counter = 0;
        while( ($row = fgetcsv($file, 4096, ',', '"')) != false ) {        
			if ($row[0] != $previousSku) {
				$previousSku = $row[0];
				$product = $this->product_model->get_by_sku_pd($row[0], $this->config->item('def_language_id'));
			}

	        if ((isset($product)) && (is_object($product))) {			
				$sizeObj = $this->size_model->get_by_size($row[1]);	
				if (is_object($sizeObj)) {
					//if (!$this->product_size_model->getRelation($product->id, $sizeObj->id)) {
						$this->product_size_model->fields['local_id'] = $product->id;
						$this->product_size_model->fields['foreign_id'] = $sizeObj->id;
						$this->product_size_model->fields['price'] = (double) $row[2];
						$this->product_size_model->fields['imported'] = 1;
						$newRelationObj = $this->product_size_model->fields_to_object();
						
						$newRelationObj->insert();
					//}	
				}
	        }	
			echo $row[0] . ' ---> ' . $row[1] . '<br />';
	        ob_flush();
	        flush(); 
			$counter++;
			/*if ($counter == 20) {
				break;
			}*/
		}
		$this->db->trans_commit();		
	}
	
	/**
	 * 
	 * Removes the marked records
	 */
	protected function process5() {
		$this->product_model->delete('marked_deletion = 1');	
		$this->category_model->delete('marked_deletion = 1');	
		$this->product_category_model->delete('marked_deletion = 1');	
	}	
	
	protected  function process6() {
		$products = $this->product_model->getAll(array('sku_left' => 'PD'))->result();
		if (!empty($products)){
			foreach($products as $product){
				if ($product->parent_id == 0){
					$oldSku = $product->sku_pd;
				}
				$product->sku = 'RD' . substr($product->sku_pd, 2);
				
				$product->name = str_replace($oldSku, $product->sku, $product->name);
				$product->product_name = str_replace($oldSku, $product->sku, $product->product_name);
				$product->description = str_replace($oldSku, $product->sku, $product->description);
				$product->short_description = str_replace($oldSku, $product->sku, $product->short_description);
				
				$prodArray = get_object_vars($product);
				$prodObj = new Product_model();
				$prodObj = $prodObj->from_array($prodArray);
				
				$prodObj->update();
			}
		}
	}
	/**
	 * 
	 * Creates the node
	 * @param array $cat
	 * @param int $parent
	 * @param int $level
	 * @param int $product
	 */
	private function createNode($categoryRow, $parent, $level, $product) {
		if (isset($categoryRow[$level])) {
			$catObj = $this->category_model->existsCategory($categoryRow[$level], $parent, $this->config->item('def_language_id'));
			$catId = 0;
			if (is_object($catObj)) {
				$catId = $catObj->id;
				$catObj->marked_deletion = 0;
				$catObj->imported = 1;
				$catObj->update(); 
			}
			if (!$catId) {
				$this->category_model->fields['name'] = trim($categoryRow[$level]);
				$this->category_model->fields['parent_id'] = $parent;
				$this->category_model->fields['imported'] = 1;
				$this->category_model->fields['language_id'] = $this->config->item('def_language_id');
				$catObj = $this->category_model->fields_to_object();
				$catId = $catObj->insert();
				
				//connect cat+product
				$this->product_category_model->fields['local_id'] = $product;
				$this->product_category_model->fields['foreign_id'] = $catId;
				$this->product_category_model->fields['imported'] = 1;	

				$relObj = $this->product_category_model->fields_to_object();
				$relObj->insert();		
						
				$level++;
				$this->createNode($categoryRow, $catId, $level, $product);
			}
			else {
				$relation = $this->product_category_model->getRelation($product, $catId);
				if (is_object($relation)) {
					$relation->marked_deletion = 0;
					$relation->imported = 1;
					
					$relation->update();
				}
				else {
					$this->product_category_model->fields['local_id'] = $product;
					$this->product_category_model->fields['foreign_id'] = $catId;
					$this->product_category_model->fields['imported'] = 1;		

					$relObj = $this->product_category_model->fields_to_object();
					$relObj->insert();
				}
				$level++;
				$this->createNode($categoryRow, $catId, $level, $product);				
			}	
			
		}		
	}

	/**
	 * 
	 * Extract the file name from a dir structure
	 * @param string $dir
	 * @return string
	 */
	private function obtainFileName($dir) {
		$dirParts = explode('/', $dir);
		
		return (isset($dirParts[count($dirParts)-1])) ? $dirParts[count($dirParts)-1] : '';
		
	}
	
	/**
	 * 
	 * Syncs the translation
	 * @param integer $id
	 * @param array $fromCsv
	 */
	private function syncTranslation($id, $fromCsv) {
		$allowedItems = array_intersect_key  ($fromCsv, $this->config->item('FEED_SYNC_IN_TRANSLATIONS'));
		$toSync = array();
		foreach ($this->toSyncInTranslations as $key) {
			if (isset($fromCsv[$key])) {
				$toSync[$key] = $fromCsv[$key];	
				
				if ($key == 'name' || $key == 'product_name' || $key == 'description' || $key == 'short_description'){
					$sku = 'RD' . substr($fromCsv['sku'], 2);
				
					$toSync[$key] = str_replace($fromCsv['sku'], $sku, $toSync[$key]);
				}
				
			}
		}
		$this->product_model->updateExternData($toSync, $id);
	}
	
	/**
	 * 
	 * Syncs the existing object if is needed
	 * @param object $existing
	 * @param object $fromCsv
	 */
	private function sync($existing, $fromCsv) {
		$syncedFields = array();
		foreach ($fromCsv as $key => $value) {
			if (($fromCsv->$key != $existing->$key) && (!in_array($key, $this->notSyncInTranslations))) {
				if (((empty($fromCsv->$key)) && (empty($existing->$key))) || ($fromCsv->$key == '' && $existing->$key == '0000-00-00 00:00:00')) {
					continue;
				}
				
				//tinymce <p></p>
				if (strip_tags($fromCsv->$key) == strip_tags($existing->$key)) {
					continue;
				}
				
				//carat weight in db numeric in csv the empty field = 0
				if (($fromCsv->$key == '') && ($existing->$key == 0)) {
					continue;
				}		
						
				$existing->$key = $value; 
				if ($key == 'name' || $key == 'product_name' || $key == 'description' || $key == 'short_description'){
					$sku = 'RD' . substr($fromCsv->sku, 2);
				
					$existing->$key = str_replace($fromCsv->sku, $sku, $existing->$key);
				}
				$syncedFields[] =$key;				
			}	
		}
		if (!empty($syncedFields)) {
			$existing->sync_fields = serialize($syncedFields);
			$existing->marked_deletion = 0;
			$existing->sync = 1;
			$existing->sync_date = date ('Y-m-d h:i:s');
			$existing->update();	
			
			return true;
		}
		
		return false;
	}
	
	
}